///////////////////////////////////////////////////////////////////////////////////////////////////
// A9Codec_zxtune.h
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "A9Codec_zxtune.h"
#include <map>
#include <vector>

// make sure the paths to the libs are ok
#pragma comment( lib, "..\\Libs\\zxtune\\Release\\zxtune.lib" )

//static instance
a9Codec_zxtune::NameToHandle a9Codec_zxtune::CachedModules;

///////////////////////////////////////////////////////////////////////////////////////////////////
a9Codec_zxtune::a9Codec_zxtune()
  : Player()
{
	guard(a9Codec_zxtune::a9Codec_zxtune);
	m_type	= A9_CODEC_ZXTUNE;
	unguard();
}

a9Codec_zxtune::~a9Codec_zxtune()
{
	guard(a9Codec_zxtune::~a9Codec_zxtune);
	unguard();
}

int a9Codec_zxtune::Init()
{
	guard(a9Codec_zxtune::Init);
	return A9_OK;
	unguard();
}

int a9Codec_zxtune::Done()
{
	guard(a9Codec_zxtune::Done);
	for (NameToHandle::const_iterator it = CachedModules.begin(), lim = CachedModules.end(); it != lim; ++it)
	{
		ZXTune_CloseModule(it->second);
	}
	CachedModules.clear();
	return A9_OK;
	unguard();
}

int	a9Codec_zxtune::Open( char* name )
{
	guard(a9Codec_ztune::Open);
	if(m_status!=A9_CODEC_CLOSED) return A9_FAIL;

	while (const ZXTuneHandle module = OpenModule(name))
	{
		ZXTuneModuleInfo modInfo;
		if (!ZXTune_GetModuleInfo(module, &modInfo))
		{
		  break;
		}
		AutoHandle<ZXTuneHandle> player(ZXTune_CreatePlayer(module), &ZXTune_DestroyPlayer);
		if (!player.Get())
		{
		  break;
		}
		int frequency = 0;
		int frameDurationMicrosec = 0;
		if (!ZXTune_GetPlayerParameterInt(player.Get(), "zxtune.sound.frequency", &frequency)
	     || !ZXTune_GetPlayerParameterInt(player.Get(), "zxtune.sound.frameduration", &frameDurationMicrosec)
		 || !ZXTune_SetPlayerParameterInt(player.Get(), "zxtune.core.aym.interpolation", 2))
		{
		  break;
		}

		//commit player
		//data and module are not required to keep for player
		Player = player;

		m_info.m_frequency = frequency;
		m_info.m_depth = 16;
		m_info.m_signed = false;
		m_info.m_channels = 2;
		m_info.m_size = static_cast<int>(int64(frameDurationMicrosec) * frequency * modInfo.Frames / 1000000);
		m_status = A9_CODEC_OPENED;
		return A9_OK;
	}
	return A9_FAIL;
	unguard();
}

int	a9Codec_zxtune::BeginRender( int pos, int loop )
{
	guard(a9Codec_zxtune::BeginRender);
	if(m_status!=A9_CODEC_OPENED) return A9_FAIL;

  ZXTune_SetPlayerParameterInt(Player.Get(), "zxtune.sound.looped", loop);
	m_loop = loop;
  ZXTune_SeekSound(Player.Get(), pos);

	m_status = A9_CODEC_RENDERING;
	return A9_OK;
	unguard();
}

int	a9Codec_zxtune::Render( byte* buffer, int size )
{
	guard(a9Codec_zxtune::Render);
	if(m_status!=A9_CODEC_RENDERING) return A9_FAIL;
	if(size<=0) return A9_FAIL;
  return ZXTune_RenderSound(Player.Get(), buffer, size);
	unguard();
}

int	a9Codec_zxtune::EndRender()
{
	guard(a9Codec_zxtune::EndRender);
	if(m_status!=A9_CODEC_RENDERING) return A9_FAIL;
  ZXTune_ResetSound(Player.Get());
	m_status = A9_CODEC_OPENED;
	return A9_OK;
	unguard();
}

int	a9Codec_zxtune::Close()
{
	guard(a9Codec_zxtune::Close);
	if(m_status!=A9_CODEC_OPENED) return A9_FAIL;
  Player.Reset();
	m_status = A9_CODEC_CLOSED;
	return A9_OK;
	unguard();
}

ZXTuneHandle a9Codec_zxtune::OpenModule(char* name)
{
	const NameToHandle::const_iterator it = CachedModules.find(name);
	if (it != CachedModules.end())
	{
		return it->second;
	}
	AutoHandle<F9FILE, int> file(F9_FileOpen(name), &F9_FileClose);
	if (!file.Get())
	{
		return 0;
	}
	const int size = F9_FileSize(file.Get());
	std::vector<byte> buffer(size);
	if (F9_FileRead(&buffer[0], size, file.Get()) <= 0)
	{
		return 0;
	}
	AutoHandle<ZXTuneHandle> data(ZXTune_CreateData(&buffer[0], buffer.size()), &ZXTune_CloseData);
	if (!data.Get())
	{
		return 0;
	}
	if (const ZXTuneHandle module = ZXTune_OpenModule(data.Get()))
	{
		CachedModules.insert(NameToHandle::value_type(name, module));
		return module;
	}
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
